﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Reflection;
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;


namespace System
{
    /// <summary>
    /// 实体对象基类
    /// </summary>
    [Serializable]
    public class BaseModel : IBaseModel
    {
        /// <summary>
        /// 属性更改前发生
        /// </summary>
        public event EventHandler<HPropertyChangingEventArgs> PropertyChanging;
        /// <summary>
        /// 属性更改后发生
        /// </summary>
        public event EventHandler<HPropertyChangedEventArgs> PropertyChanged;
        /// <summary>
        /// 对象Load后发生
        /// </summary>
        public event EventHandler OnLoadedEvent;
        /// <summary>
        /// 对象Load前发生
        /// </summary>
        public event EventHandler OnLoadingEvent;
        /// <summary>
        /// 对象提交前发生
        /// </summary>
        public event EventHandler OnSubmitingEvent;
        /// <summary>
        /// 对象提交后发生
        /// </summary>
        public event EventHandler OnSubmitedEvent;

        /// <summary>
        /// 
        /// </summary>
        public BaseModel()
        {
            Relations = new List<RelationInfo>();
            CanNotNullFields = new List<string>();
            Fields = new List<string>();

            InitProprty();

            this.OnBaseModelCreated();
        }

        void InitProprty()
        {
            ModifyInfos = new Dictionary<string, ModifyInfo>();
            Steps = new List<ModifyInfo>();
            IsNew = new bool(); IsNew = true;
            IsGetDataFromDB = new bool(); IsGetDataFromDB = false;
            CurrentStep = 0;
        }

        #region 属性

        /// <summary>
        /// 主键名称
        /// </summary>        
        protected string PrimaryKey { get; set; }
        /// <summary>
        /// 树形结构的关联字段列表
        /// </summary>        
        protected string ParentKey { get; set; }
        /// <summary>
        /// 字段列表集合
        /// </summary>        
        public List<string> Fields { get; set; }
        /// <summary>
        /// 关联关系集合
        /// </summary>        
        public List<RelationInfo> Relations { get; set; }
        /// <summary>
        /// 数据修改状态，true,修改状态，false，从数据库获取数据状态。
        /// </summary>        
        protected bool IsGetDataFromDB { get; set; }
        /// <summary>
        /// 是否需要记录修改日志
        /// </summary>        
        protected bool IsNeedRecordModify { get; set; }
        /// <summary>
        /// 不可为空的字段集合
        /// </summary>        
        public List<string> CanNotNullFields { get; set; }
        /// <summary>
        /// 是否为新增数据
        /// </summary>        
        protected bool IsNew { get; set; }
        /// <summary>
        /// 修改列表
        /// </summary> 
        protected Dictionary<string, ModifyInfo> ModifyInfos { get; set; }
        /// <summary>
        /// 修改步骤
        /// </summary>
        public List<ModifyInfo> Steps { get; set; }
        /// <summary>
        /// 当前步骤
        /// </summary>
        protected int CurrentStep { get; set; }

        public string DBName { get; set; }

        #endregion

        #region Method

        /// <summary>
        /// 属性修改前发生，并引发属性修改前事件
        /// </summary>
        /// <param name="modifyInfo"></param>
        protected virtual void SendPropertyChanging(ModifyInfo modifyInfo)
        {
            if ((this.PropertyChanging != null))
            {
                this.PropertyChanging(this, new HPropertyChangingEventArgs(modifyInfo.Field, modifyInfo));
            }
        }

        /// <summary>
        /// 属性修改后发生，并引发属性修改后事件
        /// </summary>
        /// <param name="modifyInfo">对象更改记录</param>
        protected virtual void SendPropertyChanged(ModifyInfo modifyInfo)
        {
            if ((this.PropertyChanged != null))
            {
                this.PropertyChanged(this, new HPropertyChangedEventArgs(modifyInfo.Field, modifyInfo));
            }
        }


        public virtual void OnDeleting()
        { }
        public virtual void OnDeleted()
        { }

        /// <summary>
        /// 属性修改前发生
        /// </summary>
        /// <param name="info">对象更改记录</param>
        protected virtual void OnPropertyChanging(ModifyInfo info)
        {
            PropertyInfo proInfo = CReflection.GetPropertyInfo(this.GetType(), info.Field);

            ModelFieldAttribute attribute = CModel.GetModelFieldAttribute(proInfo);

            string sInfo = "";

            if ((!attribute.IsAllowNull) && (info.NewValue == null || string.IsNullOrEmpty(info.NewValue.ToString())))
            {
                sInfo =  info.Description + "不允许为空!";
            }

            if (attribute.DbType.IndexOf("char") >= 0 && (info.NewValue != null && attribute.Size != 0 && StringHelper.GetStrLength(info.NewValue.ToString()) > attribute.Size))
            {
                if (info.NewValue.GetType() == typeof(string))
                {
                    sInfo = info.Description + "超出长度限制!";
                    
                }
            }

            if (!string.IsNullOrEmpty(attribute.ValidationExpression) && info.NewValue != null)
            {
                if (!CRegex.IsMatch(info.NewValue.ToString(), attribute.ValidationExpression))
                {
                    sInfo = info.Description + "格式不正确!";
                }
            }

            if (!string.IsNullOrEmpty(sInfo))
            {
                MyException ex = new MyException(sInfo, "BaseModel OnPropertyChanging(ModifyInfo info);");
                ex.Tag = info;
                throw ex;
            }
        }

        /// <summary>
        /// 当属性修改后发生
        /// </summary>
        /// <param name="info">修改日志</param>
        protected virtual void OnPropertyChanged(ModifyInfo info)
        {
            //if (CurrentStep < Steps.Count)
            //{
            //    Steps.RemoveRange(CurrentStep, Steps.Count - CurrentStep);
            //}
            //Steps.Insert(info);
            // CurrentStep++;


            if (ModifyInfos.ContainsKey(info.Field))
            {
                ModifyInfo temp = ModifyInfos[info.Field];
                info.OldValue = temp.OldValue;

                ModifyInfos[info.Field] = info;
            }
            else
            {
                ModifyInfos.Add(info.Field, info);
            }
        }

        /// <summary>
        /// 对象创建时发生
        /// </summary>
        protected virtual void OnBaseModelCreated()
        {

        }
        /// <summary>
        /// 对象从数据库获取后发生
        /// </summary>
        public virtual void OnLoaded()
        {
            this.IsGetDataFromDB = false;

            if (OnLoadedEvent != null)
            {
                OnLoadedEvent(this, new EventArgs());
            }
        }
        /// <summary>
        /// 对象从数据库获取后发生
        /// </summary>
        public virtual void OnLoading()
        {
            ModifyInfos = new Dictionary<string, ModifyInfo>();
            Steps = new List<ModifyInfo>();

            this.IsGetDataFromDB = new bool();
            this.IsGetDataFromDB = true;
            this.IsNew = new bool();
            this.IsNew = false;

            if (OnLoadingEvent != null)
            {
                OnLoadingEvent(this, new EventArgs());
            }
        }
        /// <summary>
        /// 对象验证方法
        /// </summary>
        protected virtual void OnValidate()
        {
            if (IsNew)
            {
                foreach (string field in CanNotNullFields)
                {
                    if (CModel.GetProValue<object>(field, this) == null)
                    {
                        throw new MyException("数据验证时出错，'属性'" + field + "'不允许为空!", "protected virtual void OnValidate(); ");
                    }

                }
            }
        }
        /// <summary>
        /// 对象提交之前发生
        /// </summary>
        public void OnSubmiting()
        {
            if (OnSubmitingEvent != null)
            {
                OnSubmitingEvent(this, new EventArgs());
            }
            OnValidate(); OnSubmit();
        }
        /// <summary>
        /// 对象提交之前发生
        /// </summary>
        protected virtual void OnSubmit() { }
        /// <summary>
        /// 对象提交之后发生
        /// </summary>
        public virtual void OnSubmited()
        {
            if (OnSubmitedEvent != null)
            {
                OnSubmitedEvent(this, new EventArgs());
            }
            this.ModifyInfos = new Dictionary<string, ModifyInfo>();
            this.Steps = new List<ModifyInfo>();

            IsNew = false;
        }

        /// <summary>
        /// 克隆当前对象，深层克隆效率较低
        /// </summary>
        /// <returns>克隆后的对象</returns>
        public virtual object Clone()
        {
            object result;
            MemoryStream memoryStream = new MemoryStream();
            BinaryFormatter formatter = new BinaryFormatter();
            formatter.Serialize(memoryStream, this);
            memoryStream.Position = 0;
            result = formatter.Deserialize(memoryStream);
            return result;
        }

        /// <summary>
        /// 克隆当前对象
        /// </summary>
        /// <param name="isMemberwiseClone">是否进行浅表副本克隆，否则执行深层克隆</param>
        /// <returns>克隆后的对象</returns>
        public virtual object Clone(bool isMemberwiseClone)
        {
            object result;

            if (isMemberwiseClone)
            {
                result = this.MemberwiseClone();
                this.OnMemberwiseClone();
            }
            else
            {
                result = this.Clone();
            }

            return result;
        }

        /// <summary>
        /// 设置是否需要记录该对象的修改日志
        /// </summary>
        /// <param name="isNeedRecordModify">是否需要记录该对象的修改日志</param>
        public void SetIsNeedRecordModify(bool isNeedRecordModify)
        {
            IsNeedRecordModify = isNeedRecordModify;
        }

        /// <summary>
        /// 获取是否需要记录该对象的修改日志
        /// </summary>
        /// <returns>是否需要记录该对象的修改日志</returns>
        public bool GetIsNeedRecordModify()
        {
            return IsNeedRecordModify;
        }

        /// <summary>
        /// 获取对象主键
        /// </summary>
        /// <returns>对象主键</returns>
        public string GetPrimaryKey()
        {
            return PrimaryKey;
        }

        /// <summary>
        /// 设置对象主键
        /// </summary>
        /// <param name="primaryKey">对象主键</param>
        public void SetPrimaryKey(string primaryKey)
        {
            PrimaryKey = primaryKey;
        }

        /// <summary>
        /// 获取对象父键
        /// </summary>
        /// <returns>对象父键</returns>
        public string GetParentKey()
        {
            return ParentKey;
        }

        /// <summary>
        /// 设置对象父键
        /// </summary>
        /// <param name="parentKey">对象父键</param>
        public void SetParentKey(string parentKey)
        {
            ParentKey = parentKey;
        }

        /// <summary>
        /// 设置对象主键值
        /// </summary>
        public virtual void SetPrimaryKeyValue()
        {
            ModelFieldAttribute attribute = CReflection.GetModelFieldAttribute(this, PrimaryKey);
            if (!attribute.IsDbGenerated)
            {
                string primaryKeyValue = InitId(PrimaryKey);
                CModel.SetProValue(this, PrimaryKey, primaryKeyValue);
            }
        }

        public virtual Dictionary<string, ModifyInfo> GetModifyInfos()
        {
            return this.ModifyInfos;
        }

        public virtual void SetModifyInfos(Dictionary<string, ModifyInfo> modifyInfos)
        {
            this.ModifyInfos = modifyInfos;
        }
        ///// <summary>
        ///// 获取主键值
        ///// </summary>
        ///// <param name="proName">主键名称</param>
        ///// <returns>值</returns>
        //protected virtual string InitId(string proName, string tableName, DBType type)
        //{
        //    DalBase dal = new DalBase(type);

        //    System.Data.IDataParameter parameterTableName = DataHelper.GetDataParameter(type, "@TableName", tableName);
        //    parameterTableName.DbType = System.Data.DbType.String;


        //    System.Data.IDataParameter parameterNewId = DataHelper.GetDataParameter(type);
        //    parameterNewId.DbType = System.Data.DbType.String;
        //    parameterNewId.ParameterName = "@NewId";
        //    parameterNewId.Direction = System.Data.ParameterDirection.Output;
        //    ((System.Data.SqlClient.SqlParameter)parameterNewId).Size = 50;

        //    List<IDataParameter> parameters = new List<IDataParameter>();
        //    parameters.Insert(parameterTableName);
        //    parameters.Insert(parameterNewId);

        //    dal.ExecuteNonQuery("PR_MakeMaxReportNO", CommandType.StoredProcedure , parameters);

        //    return Convert.ToString(parameterNewId.Value);
        //}

        /// <summary>
        /// 获取主键值
        /// </summary>
        /// <param name="proName">主键名称</param>
        /// <returns>值</returns>
        protected virtual string InitId(string proName)
        {
            return Guid.NewGuid().ToString();
        }
        /// <summary>
        /// 进行浅层拷贝后发生
        /// </summary>
        public virtual void OnMemberwiseClone()
        {
            ModifyInfos = new Dictionary<string, ModifyInfo>();
            Steps = new List<ModifyInfo>();

            this.SetPrimaryKeyValue();
            this.IsNew = new bool();
            IsNew = true;
            this.IsGetDataFromDB = new bool();
            IsGetDataFromDB = false;
        }

        /// <summary>
        /// 获取是否为新增对象数据
        /// </summary>
        /// <returns>是否为新增对象数据</returns>
        public bool GetIsNew()
        {
            return IsNew;
        }

        public void FirstStep()
        {

        }

        public void LastStep()
        {

        }

        public void NextStep()
        {

        }

        public void PreviousStep()
        {

        }

        public void NextStep(int steps)
        {

        }

        public void PreviousStep(int steps)
        {

        }

        public int GetCurrentStep()
        {
            return CurrentStep;
        }

        #endregion

        #region IBaseModel 成员


        public void SetIsNew(bool isNew)
        {
            IsNew = isNew;
        }

        #endregion
    }

    /// <summary>
    /// 实体对象接口定义
    /// </summary>
    public interface IBaseModel
    {
        List<string> Fields { get; set; }
        List<string> CanNotNullFields { get; set; }
        List<RelationInfo> Relations { get; set; }
        List<ModifyInfo> Steps { get; set; }
        void SetIsNeedRecordModify(bool isNeedRecordModify);
        bool GetIsNeedRecordModify();
        object Clone();
        object Clone(bool isMemberwiseClone);
        void OnSubmiting();
        void OnSubmited();
        void OnLoaded();
        void OnLoading();
        void SetPrimaryKeyValue();
        void OnMemberwiseClone();

        string GetPrimaryKey();
        void SetPrimaryKey(string primaryKey);

        string GetParentKey();
        void SetParentKey(string parentKey);

        bool GetIsNew();
        void SetIsNew(bool isNew);


        Dictionary<string, ModifyInfo> GetModifyInfos();
        void SetModifyInfos(Dictionary<string, ModifyInfo> modifyInfos);

        void FirstStep();
        void LastStep();
        void NextStep();
        void PreviousStep();
        void NextStep(int steps);
        void PreviousStep(int steps);
        int GetCurrentStep();
    }

    [Serializable]
    public class HPropertyChangingEventArgs : EventArgs
    {

        public ModifyInfo ModifyInfo { get; set; }
        public string PropertyName { get; set; }

        public HPropertyChangingEventArgs(string propertyName, ModifyInfo modifyInfo)
        {
            ModifyInfo = modifyInfo;
            PropertyName = propertyName;
        }
    }

    [Serializable]
    public class HPropertyChangedEventArgs : EventArgs
    {
        public ModifyInfo ModifyInfo { get; set; }
        public string PropertyName { get; set; }

        public HPropertyChangedEventArgs(string propertyName, ModifyInfo modifyInfo)
        {
            ModifyInfo = modifyInfo;
            PropertyName = propertyName;
        }
    }

}
